import socket from '@ohos.net.socket'
import wifi from "@ohos.wifi"

import UdpProcess from "./UdpProcess"

// 协议报文的反馈结果定义
export enum ProtocolResult {
  ProtocolResult_Success = 0,
  ProtocolResult_PacketLength,      // 报文长度错误
  ProtocolResult_PacketDeviceId,    // 报文设备号错误
  ProtocolResult_PacketDeviceType,  // 报文设备类型错误
  ProtocolResult_PacketCmd,         // 报文命令错误
  ProtocolResult_SelectError,       // 选中的设备号不对
  ProtocolResult_RepeatMessage,     // 重复报文
}

// deviceType的枚举
export enum ProtocolDeviceType {
  ProtocolDeviceType_Detector = 2,
}

// cmd的枚举
export enum ProtocolCmd {
  ProtocolCmd_FindDevice = 1,                 // 查找设备号
  ProtocolCmd_ReportHeartRateAndBloodOxygen,  // 上报心率血氧等数据
  ProtocolCmd_ReportBodyTemperature,          // 上报体温
  ProtocolCmd_ReportECG,                      // 上报心电图数据
  ProtocolCmd_SetDetectorType,                // 设置检测类型

  ProtocolCmd_Reboot = 0x1234,                // 设备重启
}

// 报文内容
export type ProtocolPacket = {
  deviceId: string
  deviceType: number
  cmd: number
  result: number
  data: string
}
// 报文的字符串形式
export type ProtocolStringRes = {
  result: number
  packet: string
}

// 定义心电图数据结构体
export type ProtocolEcg = {
  heart_rate: number,     // 心率数值
  data: Array<number>,
}

// 检测类型设置
export enum ProtocolDetectorType {
  ProtocolDetectorType_HeartRateAndBloodoxygen = 1,
  ProtocolDetectorType_BodyTemperator,
  ProtocolDetectorType_Ecg,
}

// 设备信息
export type ProtocolDeviceInfo = {
  deviceId: string,
  heart_rate_is_valid: boolean,
  heart_rate: number,
  blood_oxygen_is_valid: boolean,
  blood_oxygen: number,
  body_temperature_is_valid: boolean,
  body_temperature: number,
  ecg: Array<ProtocolEcg>,
}

class Protocol {
  // 报文位移
  private offset_device_id: number = 0      // 设备号位移
  private offset_device_type: number = 12   // 设备类型位移
  private offset_cmd: number = 14           // 命令位移
  private offset_result: number = 16        // 返回值位移
  private offset_data: number = 17          // 数据部分位移

  // 长度
  private length_device_id: number = 12     // 设备号长度
  private length_device_type: number = 2    // 设备类型长度
  private length_cmd: number = 2            // 命令类型长度
  private length_result: number = 1         // 反馈结果长度

  // 心电图当前帧号
  public ecg_current_packet: number = 0

  /***************************************************************
   * 函数名称: constructor
   * 说    明: 类初始化时，触发该函数
   *          初始化TCP，并配置接收回调函数
   * 参    数: 无
   * 返 回 值: 无
   ***************************************************************/
  constructor() {
  }

  /***************************************************************
   * 函数名称: clearEcgCurrentPacket
   * 说    明: 清除ecg报文帧号
   * 参    数: 无
   * 返 回 值: 无
   ***************************************************************/
  clearEcgCurrentPacket() : void {
    this.ecg_current_packet = 0
  }

  /***************************************************************
   * 函数名称: setDeviceId_Zero
   * 说    明: 设备号字符串，全部为0
   * 参    数: 无
   * 返 回 值: 返回string类型的病全部是0的设备号字符串
   ***************************************************************/
  setDeviceId_Zero(): string {
    let size: number = this.length_device_id
    let str: string = ""
    let i: number = 0

    for (i = 0; i < size; i++) {
      str += String.fromCharCode(0)
    }

    return str
  }

  /***************************************************************
   * 函数名称: getDefaultPacket
   * 说    明: 构建默认的packet
   * 参    数: 无
   * 返 回 值: 返回ProtocolPacket类型的结构体变量
   ***************************************************************/
  getDefaultPacket() : ProtocolPacket {
    let packet: ProtocolPacket = {
      deviceId: "",
      deviceType: ProtocolDeviceType.ProtocolDeviceType_Detector,
      cmd: ProtocolCmd.ProtocolCmd_FindDevice,
      result: ProtocolResult.ProtocolResult_Success,
      data: "",
    }
    return packet
  }

  /***************************************************************
   * 函数名称: print
   * 说    明: 打印报文
   * 参    数: 无
   * 返 回 值: 无
   ***************************************************************/
  print(packet: string) {
    let value = this.parsePacket(packet)

    if (value.result != ProtocolResult.ProtocolResult_Success) {
      console.log("Protocol: print => packet length is error, length=" + packet.length)
      return
    }

    // 打印设备号
    let deviceId: string = value.deviceId
    console.log("Protocol: device id => " + deviceId)
    // 打印设备类型
    let deviceType: number = value.deviceType
    console.log("Protocol: device type => " + deviceType)
    // 打印命令类型
    let cmd: number = value.cmd
    console.log("Protocol: cmd => " + cmd)
    // 打印返回值
    let res: number = value.result
    console.log("Protocol: result => " + res)
    // 打印数据部分
    let data = value.data
    console.log("Protocol: data => " + data)
    console.log("Protocol: data.charCodeAt() => " + data.charCodeAt(0))
  }

  /***************************************************************
   * 函数名称: composePacket
   * 说    明: 构建的packet
   * 参    数:
   *      @packet_protocol    ProtocolPacket类型的协议报文
   * 返 回 值:
   *      @result             返回结果，0为成功，反之为失败
   *      @packet             返回string类型的协议报文
   ***************************************************************/
  composePacket(packet_protocol: ProtocolPacket): { result: number, packet: string } {
    let res: number = ProtocolResult.ProtocolResult_Success
    let packet_string: string = ""

    // 加入设备号
    if (packet_protocol.deviceId.length < this.length_device_id) {
      // 设备号的字符串长度小于要求长度
      let i: number = 0
      packet_string = packet_protocol.deviceId
      for (i = 0; i < (this.length_device_id - packet_protocol.deviceId.length); i++) {
        packet_string += String.fromCharCode(0)
      }
      packet_string += packet_protocol.deviceId
    } else if (packet_protocol.deviceId.length > this.length_device_id) {
      // 设备号的字符串长度大于要求长度
      packet_string = packet_protocol.deviceId.substr(this.offset_device_id, this.length_device_id)
    } else {
      packet_string = packet_protocol.deviceId
    }
    // 加入设备类型
    let type_h: number = (packet_protocol.deviceType >> 8) & 0xFF
    let type_l: number = packet_protocol.deviceType & 0xFF
    packet_string += String.fromCharCode(type_h)
    packet_string += String.fromCharCode(type_l)
    // 加入命令
    let cmd_h: number = (packet_protocol.cmd >> 8) & 0xFF
    let cmd_l: number = packet_protocol.cmd & 0xFF
    packet_string += String.fromCharCode(cmd_h)
    packet_string += String.fromCharCode(cmd_l)
    // 加入返回值
    let result = packet_protocol.result & 0xFF
    packet_string += String.fromCharCode(result)
    // 添加数据部分
    packet_string += packet_protocol.data

    return { result: res, packet: packet_string }
  }

  /***************************************************************
   * 函数名称: parsePacket
   * 说    明: 解析协议报文
   * 参    数:
   *      @packet     string类型的协议报文
   * 返 回 值: 返回ProtocolPacket类型的协议报文
   ***************************************************************/
  parsePacket(packet: string): ProtocolPacket {
    let id: string = ""
    let type: number = 0
    let cmd: number = 0
    let res: number = ProtocolResult.ProtocolResult_Success
    let da: string = ""

    if (packet.length < 16) {
      res = ProtocolResult.ProtocolResult_PacketLength
    } else {
      // 获取设备号
      id = packet.substr(this.offset_device_id, this.length_device_id)
      // 获取设备类型
      let type_str: string = packet.substr(this.offset_device_type, this.length_device_type)
      let type_h: number = type_str.charCodeAt(0)
      let type_l: number = type_str.charCodeAt(1)
      type = (type_h << 8) + (type_l)
      // 获取命令
      let cmd_str: string = packet.substr(this.offset_cmd, this.length_cmd)
      let cmd_h: number = cmd_str.charCodeAt(0)
      let cmd_l: number = cmd_str.charCodeAt(1)
      cmd = (cmd_h << 8) + (cmd_l)
      // 获取返回值
      let res_str: string = packet.substr(this.offset_result, this.length_result)
      res = res_str.charCodeAt(0)
      // 获取数据内容
      da = packet.substr(this.offset_data, packet.length - this.offset_data)
    }

    let packet_protocol: ProtocolPacket = {
      deviceId: id,
      deviceType: type,
      cmd: cmd,
      result: res,
      data: da,
    }
    return packet_protocol
  }

  /***************************************************************
   * 函数名称: findDevice
   * 说    明: 搜索设备号
   * 参    数: 无
   * 返 回 值: 返回ProtocolStringRes类型的结果
   ***************************************************************/
  findDevice(): ProtocolStringRes {
    let deviceId: string = this.setDeviceId_Zero()
    let packet_protocol: ProtocolPacket = {
      deviceId: deviceId,
      deviceType: ProtocolDeviceType.ProtocolDeviceType_Detector,
      cmd: ProtocolCmd.ProtocolCmd_FindDevice,
      result: ProtocolResult.ProtocolResult_Success,
      data: "",
    }
    let value: ProtocolStringRes = this.composePacket(packet_protocol)
    return value
  }

  /***************************************************************
   * 函数名称: findDeviceRsp
   * 说    明: 解析搜索设备号的反馈包
   * 参    数:
   *      @packet     string类型的协议报文
   * 返 回 值:
   *      @result     返回结果，0为成功，反之为失败
   *      @deviceId   返回协议报文解析出来的设备编号
   ***************************************************************/
  findDeviceRsp(packet: string): {
    result: number,
    deviceId: string
  } {
    let value = this.parsePacket(packet)
    return { result: value.result, deviceId: value.deviceId }
  }

  /***************************************************************
   * 函数名称: reportHeartRateAndBloodOxygen
   * 说    明: 上报心率血氧数值
   * 参    数:
   *      @packet                 string类型的协议报文
   * 返 回 值:
   *      @result                 返回结果，0为成功，反之为失败
   *      @deviceId               返回协议报文解析出来的设备编号
   *      @heart_rate_is_valid    返回协议报文解析出来的心率是否有效
   *      @heart_rate             返回协议报文解析出来的心率数值
   *      @blood_oxygen_is_valid  返回协议报文解析出来的血氧是否有效
   *      @blood_oxygen           返回协议报文解析出来的血氧数值
   ***************************************************************/
  reportHeartRateAndBloodOxygen(packet: string) : { result: number, deviceId: string, heart_rate_is_valid: boolean, heart_rate: number, blood_oxygen_is_valid: boolean, blood_oxygen: number } {
    let value = this.parsePacket(packet)

    if (value.result != ProtocolResult.ProtocolResult_Success) {
      console.error("UdpProcess: packet: " + packet + ", result = " + value.result)
      return { result: value.result, deviceId: "", heart_rate_is_valid: false, heart_rate: 0, blood_oxygen_is_valid: false, blood_oxygen: 0 }
    }

    let hr_is_valid: boolean = (value.data.charCodeAt(0) == 0) ? (false) : (true)
    let hr: number = value.data.charCodeAt(1)
    let bo_is_valid: boolean = (value.data.charCodeAt(2) == 0) ? (false) : (true)
    let bo: number = value.data.charCodeAt(3)

    let i: number = 0
    for (i = 0; i < packet.length; i++) {
      console.log("UdpProcess: reportHeartRateAndBloodOxygen [" + i + "] = " + packet.charCodeAt(i))
    }

    return { result: value.result, deviceId: value.deviceId, heart_rate_is_valid: hr_is_valid, heart_rate: hr, blood_oxygen_is_valid: bo_is_valid, blood_oxygen: bo }
  }

  /***************************************************************
   * 函数名称: reportBodyTemperature
   * 说    明: 上报体温
   * 参    数:
   *      @packet                 string类型的协议报文
   * 返 回 值:
   *      @result                 返回结果，0为成功，反之为失败
   *      @deviceId               返回协议报文解析出来的设备编号
   *      @temperature_is_valid   返回协议报文解析出来的体温是否有效
   *      @temperature            返回协议报文解析出来的体温数值
   ***************************************************************/
  reportBodyTemperature(packet: string) : { result: number, deviceId: string, temperature_is_valid: boolean, temperature: number } {
    let value = this.parsePacket(packet)

    if (value.result != ProtocolResult.ProtocolResult_Success) {
      console.error("UdpProcess: packet: " + packet + ", result = " + value.result)
      return { result: value.result, deviceId: "", temperature_is_valid: false, temperature: 0 }
    }

    let is_valid: boolean = (value.data.charCodeAt(0) == 0) ? (false) : (true)
    let temp: number = ((value.data.charCodeAt(1) << 8) + (value.data.charCodeAt(2) << 0)) / 100

    return { result: value.result, deviceId: value.deviceId, temperature_is_valid: is_valid, temperature: temp }
  }

  /***************************************************************
   * 函数名称: reportECG
   * 说    明: 上报心电图数据
   * 参    数:
   *      @packet         string类型的协议报文
   * 返 回 值:
   *      @result         返回结果，0为成功，反之为失败
   *      @deviceId       返回协议报文解析出来的设备编号
   *      @ecg            返回协议报文解析出来的心电图数据
   ***************************************************************/
  reportECG(packet: string) : { result: number, deviceId: string, ecg: ProtocolEcg } {
    let value: ProtocolPacket = this.parsePacket(packet)
    let ecg: ProtocolEcg = {
      heart_rate: 0,
      data: [],
    }
    let i: number

    if (value.result != ProtocolResult.ProtocolResult_Success) {
      console.error("UdpProcess: packet: " + packet + ", result = " + value.result)
      return { result: value.result, deviceId: "", ecg: ecg }
    }

    // 心率
    ecg.heart_rate = value.data.charCodeAt(0)

    // 前面4个字节是帧号，可能重复
    let packet_id: number = 0
    packet_id += (value.data.charCodeAt(1) << (8 * 0))
    packet_id += (value.data.charCodeAt(2) << (8 * 1))
    packet_id += (value.data.charCodeAt(3) << (8 * 2))
    packet_id += (value.data.charCodeAt(4) << (8 * 3))
    console.log(`Protocol: reportECG => packet_id(${packet_id})`)
    // if (packet_id <= this.ecg_current_packet) {
    //   // 当前报文重复
    //   console.log("Protocol: packet_id(" + packet_id + ") <= this.ecg_current_packet(" + this.ecg_current_packet + ")")
    //   return { result: ProtocolResult.ProtocolResult_RepeatMessage, deviceId: "", ecg: ecg }
    // }

    this.ecg_current_packet = packet_id
    ecg.data = []
    for (i = 5; i < value.data.length; i += 4) {
      let tmp: number = 0
      tmp = (value.data.charCodeAt(i) << (8 * 0))
      tmp += (value.data.charCodeAt(i + 1) << (8 * 1))
      tmp += (value.data.charCodeAt(i + 2) << (8 * 2))
      tmp += (value.data.charCodeAt(i + 3) << (8 * 3))
      ecg.data.push(tmp)
    }

    return { result: value.result, deviceId: value.deviceId, ecg: ecg }
  }

  /***************************************************************
   * 函数名称: reportECGRsp
   * 说    明: 反馈心电图上报报文
   * 参    数:
   *      @packet             ProtocolPacket类型的协议报文
   *      @packet_id          心电图的帧好
   * 返 回 值:
   *      @ProtocolStringRes  返回结果
   ***************************************************************/
  reportECGRsp(packet: ProtocolPacket, packet_id: number) : ProtocolStringRes {
    packet.data = String.fromCharCode(packet_id & 0xFF)
    packet.data += String.fromCharCode((packet_id >> 8) & 0xFF)
    packet.data += String.fromCharCode((packet_id >> 16) & 0xFF)
    packet.data += String.fromCharCode((packet_id >> 24) & 0xFF)
    let res = this.composePacket(packet)
    let str: ProtocolStringRes = {
      result: res.result,
      packet: res.packet,
    }
    return str
  }

  /***************************************************************
   * 函数名称: setDetectionType
   * 说    明: 设置检测类型
   * 参    数:
   *      @deviceId         string类型的协议报文
   *      @detection_type   检测类型
   * 返 回 值:
   *      @result         返回结果，0为成功，反之为失败
   *      @packet         返回string类型的协议报文
   ***************************************************************/
  setDetectionType(deviceId: string, detection_type: number) : { result: number, packet: string } {
    let type: string = String.fromCharCode(detection_type)
    let packet_protocol: ProtocolPacket = {
      deviceId: deviceId,
      deviceType: ProtocolDeviceType.ProtocolDeviceType_Detector,
      cmd: ProtocolCmd.ProtocolCmd_SetDetectorType,
      result: ProtocolResult.ProtocolResult_Success,
      data: type,
    }
    let value = this.composePacket(packet_protocol)
    return { result: value.result, packet: value.packet }
  }
}
export default new Protocol()